use crate::types; //or use super::types;
use crate::types::Formatter;
use chrono::prelude::Local;

impl types::Book {
    /// New book
    ///
    /// # Examples
    ///
    /// ```
    /// use crate::types;
    /// let mut book = types::Book::new(1, "aaa");
    /// ```
    pub fn new(id: u64, title: &str, book_type: types::BookType) -> types::Book {
        let now = Local::now().timestamp_millis();
        types::Book {
            id: id,
            title: title.to_string(),
            created_at: now,
            updated_at: now,
            book_type: book_type,
        }
    }

    pub fn set_title(&mut self, title: &str) {
        self.title = title.to_string();
        self.updated_at = Local::now().timestamp_millis();
    }
}

pub fn book_demo() {
    let mut book1 = types::Book::new(1, "aaa", types::BookType::Rust);
    println!("book1:{:?}", book1);

    book1.id = 2;
    book1.book_type = types::BookType::Go("golang".to_string());
    println!("book1:{:?}", book1);
    book1.book_type.call();
    let bt = book1.book_type.to_string();
    println!("string book_type:{}, book:{:?}", bt, book1);

    book1.set_title("bbb");
    println!("book1:{:?}", book1);
    println!("book1 format1:{:?}", book1.format());
    println!("book1 format2:{:?}", types::format(&book1));

    let fmt = new_formatter("book");
    println!("fmt book:{:?}", fmt.format());

    let fmt2 = new_formatter2("book");
    println!("fmt2 book:{:?}", fmt2.format());

    let ret = add_book(&book1);
    println!("ret:{:?}", ret);
    match ret {
        Ok(id) => {
            println!("id:{}", id);
        }
        Err(err) => {
            println!("err:{:?}", err);
        }
    }
    println!("add book1 end:{:?}", book1);
}

fn add_book(book: &types::Book) -> Result<u64, types::BookError> {
    println!("add book start, {:?}", book);
    if book.id == 1 {
        return Ok(book.id);
    }

    Err(types::BookError {
        code: 1,
        message: "add book failed".to_string(),
    })
}

fn new_formatter(ftype: &str) -> impl types::Formatter {
    match ftype {
        "book" => types::Book::new(1, "aaa", types::BookType::Rust),
        //"user" => types::User::new(1, "xxx"),
        &_ => {
            panic!("type invalid")
        }
    }
}

fn new_formatter2(ftype: &str) -> Box<dyn types::Formatter> {
    match ftype {
        "book" => Box::new(types::Book::new(1, "aaa", types::BookType::Rust)),
        "user" => Box::new(types::User::new(1, "xxx", types::UserCategory::Go, None)),
        &_ => {
            panic!("type invalid")
        }
    }
}
